"""
分页组件应用：
1. 在视图函数中
    queryset = models.Issues.objects.filter(project_id=project_id)
    page_object = Pagination(
        current_page=request.GET.get('page'),
        all_count=queryset.count(),
        base_url=request.path_info,
        query_params=request.GET
    )
    issues_object_list = queryset[page_object.start:page_object.end]

    context = {
        'issues_object_list': issues_object_list,
        'page_html': page_object.page_html()
    }
    return render(request, 'issues.html', context)
2. 前端
    {% for item in issues_object_list %}
        {{item.xxx}}
    {% endfor %}

     <nav aria-label="...">
        <ul class="pagination" style="margin-top: 0;">
            {{ page_html|safe }}
        </ul>
    </nav>
"""


class Pagination(object):
    def __init__(self, current_page, all_count, base_url, query_params, per_page=30, pager_page_count=11):
        """
        分页初始化
        :param current_page: 当前页码
        :param per_page: 每页显示数据条数
        :param all_count: 数据库中总条数
        :param base_url: 基础URL
        :param query_params: QueryDict对象，内部含所有当前URL的原条件
        :param pager_page_count: 页面上最多显示的页码数量
        """
        # 前端分页页码显示
        #初始化 base_url
        self.base_url = base_url # 保存基础 URL，生成分页链接时会用到。
        try:
            self.current_page = int(current_page) # 尝试将传入的当前页码转换为整数。
            if self.current_page <= 0:    # 如果转换后的页码小于等于 0，则强制设置为 1。
                self.current_page = 1
        except Exception as e:
            self.current_page = 1  # 如果传入的页码无法转换为整数（如传入字符串），则默认当前页为 1。
        query_params = query_params.copy()   # 复制 QueryDict 对象，以避免修改原始的请求参数。
        query_params._mutable = True       # 将 QueryDict 对象设置为可变，这样可以对它进行修改。
        self.query_params = query_params    # 将可变的 QueryDict 对象保存到实例变量中。
        self.per_page = per_page            # 每页显示的记录数，默认值为 30。
        self.all_count = all_count         # 数据总条数。
        self.pager_page_count = pager_page_count  # 页面上显示的最大页码数量，默认值为 11。
        # 计算总页数（即总页码数）
        pager_count, b = divmod(all_count, per_page)    # 使用 divmod 计算总页数和余数。
        if b != 0:
            pager_count += 1    # 如果有余数，则总页数加 1（既有剩余的记录要显示在新的一页上）。
        self.pager_count = pager_count     # 保存总页数。
        # 计算页码数量的一半，用于确定页码的显示范围
        half_pager_page_count = int(pager_page_count / 2)
        self.half_pager_page_count = half_pager_page_count   # 保存页码数量的一半，用于在后续计算页码显示范围时使用。

    @property
    def start(self):
        """
        数据获取值起始索引
        :return:
        """
        return (self.current_page - 1) * self.per_page   # 例如，当前页为 1，则起始索引为 0（第一页从第 0 条记录开始）。

    @property
    def end(self):
        """
        数据获取值结束索引
        :return:
        """
        return self.current_page * self.per_page   # 例如，当前页为 1，per_page 为 30，则结束索引为 30。

    def page_html(self):
        """
        生成HTML页码
        :return:
        """
        if self.all_count == 0: # 如果总记录数为 0，则返回空字符串。
            return ""

        # 如果数据总页码pager_count<11 pager_page_count
        if self.pager_count < self.pager_page_count:  # 如果总页数少于最大显示页码数，则显示从第一页到最后一页的页码
            pager_start = 1
            pager_end = self.pager_count
        else:   # 如果总页数超过最大显示页码数
            # 数据页码已经超过11
            # 判断： 如果当前页 <= 5 half_pager_page_count
            if self.current_page <= self.half_pager_page_count:
                pager_start = 1  # 当前页在页码范围的前半部分，显示从第一页开始的页码
                pager_end = self.pager_page_count
            else:# 当前页在页码范围的后半部分，计算显示的页码范围
                # 如果： 当前页+5 > 总页码
                if (self.current_page + self.half_pager_page_count) > self.pager_count:
                    # 如果当前页靠近末尾，显示最后一段页码
                    pager_end = self.pager_count
                    pager_start = self.pager_count - self.pager_page_count + 1
                else:
                    # 正常情况，当前页在中间部分，前后显示 half_pager_page_count 个页码
                    pager_start = self.current_page - self.half_pager_page_count
                    pager_end = self.current_page + self.half_pager_page_count

        page_list = []  # 存储生成的页码 HTML 片段。
        # 生成“上一页”链接
        if self.current_page <= 1:   # 如果当前页是第一页，上一页链接不可点击。
            prev = '<li><a href="#">上一页</a></li>'
        else:
            self.query_params['page'] = self.current_page - 1  # 设置上一页的页码。
            prev = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url, self.query_params.urlencode()) # 生成上一页的 HTML 链接。
        page_list.append(prev) # 添加到页码列表。
        # 生成具体页码的链接
        for i in range(pager_start, pager_end + 1):  # 循环生成从 pager_start 到 pager_end 的页码。
            self.query_params['page'] = i     # 设置当前页码。
            if self.current_page == i:         # 如果当前页码等于当前页面的页码，设置为激活状态。
                tpl = '<li class="active"><a href="%s?%s">%s</a></li>' % (
                    self.base_url, self.query_params.urlencode(), i,)
            else:
                tpl = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.query_params.urlencode(), i,)
            page_list.append(tpl)   # 将生成的 HTML 片段添加到列表中。

        if self.current_page >= self.pager_count:    # 如果当前页是最后一页，下一页链接不可点击。
            nex = '<li><a href="#">下一页</a></li>'
        else:
            self.query_params['page'] = self.current_page + 1 # 设置下一页的页码。
            nex = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url, self.query_params.urlencode(),)
        page_list.append(nex)  # 添加到页码列表。

        # 生成总数据和页码信息
        if self.all_count:
            tpl = "<li class='disabled'><a>共%s条数据，页码%s/%s页</a></li>" % (
            self.all_count, self.current_page, self.pager_count,)
            page_list.append(tpl)    # 将总数据条数和页码信息添加到页码列表中。
        # 拼接所有的页码 HTML 片段
        page_str = "".join(page_list)    # 将所有 HTML 片段拼接成一个字符串。
        return page_str     # 返回生成的页码 HTML 字符串。
